// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.

package com.linqingying.gitcode.extensions

import com.intellij.collaboration.auth.AccountManager
import com.intellij.collaboration.auth.DefaultAccountHolder
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.DumbProgressIndicator
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project
import git4idea.remote.hosting.http.HostedGitAuthenticationFailureManager
import git4idea.remote.hosting.http.SilentHostedGitHttpAuthDataProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import com.linqingying.gitcode.api.GitCodeApiRequestExecutor
import com.linqingying.gitcode.api.data.GitCodeAuthenticatedUser
import com.linqingying.gitcode.authentication.accounts.GCAccountManager
import com.linqingying.gitcode.authentication.accounts.GitCodeAccount
import com.linqingying.gitcode.authentication.accounts.GitCodeAccountInformationProvider
import com.linqingying.gitcode.authentication.accounts.GitCodeProjectDefaultAccountHolder

private val LOG = logger<GCSilentHttpAuthDataProvider>()

internal class GCSilentHttpAuthDataProvider : SilentHostedGitHttpAuthDataProvider<GitCodeAccount>() {
  override val providerId: String = "GitCode Plugin"

  override val accountManager: AccountManager<GitCodeAccount, String>
    get() = service<GCAccountManager>()

  override fun getDefaultAccountHolder(project: Project): DefaultAccountHolder<GitCodeAccount> {
    return project.service<GitCodeProjectDefaultAccountHolder>()
  }

  override fun getAuthFailureManager(project: Project): HostedGitAuthenticationFailureManager<GitCodeAccount> {
    return project.service<GCGitAuthenticationFailureManager>()
  }

  override suspend fun getAccountLogin(account: GitCodeAccount, token: String): String? {
    return getAccountDetails(account, token)?.login
  }

  companion object {
    suspend fun getAccountsWithTokens(project: Project, url: String): Map<GitCodeAccount, String?> {
      val accountManager = service<GCAccountManager>()
      val authFailureManager = project.service<GCGitAuthenticationFailureManager>()

      return getAccountsWithTokens(accountManager, authFailureManager, url)
    }

    suspend fun getAccountDetails(account: GitCodeAccount, token: String): GitCodeAuthenticatedUser? =
      try {
        val executor = GitCodeApiRequestExecutor.Factory.getInstance().create(account.server, token)
        withContext(Dispatchers.IO) {
          service<GitCodeAccountInformationProvider>().getInformation(executor, DumbProgressIndicator(), account)
        }
      }
      catch (e: Exception) {
        if (e !is ProcessCanceledException) LOG.info("Cannot load details for $account", e)
        null
      }
  }
}
